// ==UserScript==
// @name         微信公众号音频下载器
// @namespace    https://www.52pojie.cn/home.php?mod=space&uid=386547
// @version      1.2
// @description  下载微信公众号文章中的音频，智能命名文件
// @AuThor       吾爱破解 等待穿山乙
// @match        https://mp.weixin.qq.com/*
// @match        https://*.mp.weixin.qq.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// @connect      res.wx.qq.com
// @require      https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js
// @icon         https://gitee.com/selling-surprises/Greasyfork-Script-repository/raw/main/%E5%90%84%E5%A4%A7%E5%B9%B3%E5%8F%B0/%E5%BE%AE%E4%BF%A1/wechat.png
// ==/UserScript==

(function() {
    'use strict';

    // 创建下载按钮样式
    const style = document.createElement('style');
    style.textContent = `
        .audio-download-btn {
            background: #07c160;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            margin: 10px 0;
            transition: background 0.3s;
        }
        .audio-download-btn:hover {
            background: #06ae56;
        }
        .audio-download-btn:disabled {
            background: #cccccc;
            cursor: not-allowed;
        }
        .download-status {
            margin-left: 10px;
            font-size: 12px;
            color: #666;
        }
        .audio-download-container {
            margin: 10px 0;
            padding: 10px;
            border: 1px solid #eaeaea;
            border-radius: 4px;
            background: #f9f9f9;
        }
        .audio-info {
            font-size: 12px;
            color: #888;
            margin-top: 5px;
            word-break: break-all;
        }
        .filename-preview {
            font-size: 12px;
            color: #333;
            margin: 5px 0;
            padding: 5px;
            background: #fff;
            border-radius: 3px;
            border-left: 3px solid #07c160;
        }
    `;
    document.head.appendChild(style);

    // 清理标题中的括号内容
    function cleanTitle(title) {
        // 先处理中文括号及其内容
        let cleaned = title.replace(/[\(（][^\)）]*[\)）]/g, '');

        // 处理可能残留的空格和标点
        cleaned = cleaned.replace(/\s+\./g, '.')
                        .replace(/\s+$/g, '')
                        .replace(/^\s+/g, '')
                        .replace(/\s{2,}/g, ' ')
                        .replace(/[_\-\—]+$/g, '') // 删除末尾的下划线、破折号等
                        .trim();

        return cleaned;
    }

    // 获取文章标题
    function getArticleTitle() {
        // 方法1: 从og:title获取
        const ogTitle = document.querySelector('meta[property="og:title"]');
        if (ogTitle) {
            let title = ogTitle.getAttribute('content');
            title = cleanTitle(title);
            return title;
        }

        // 方法2: 从页面标题获取
        const pageTitle = document.title;
        if (pageTitle && !pageTitle.includes('微信')) {
            let title = pageTitle.replace(/ - 微信公众号$/, '');
            title = cleanTitle(title);
            return title;
        }

        // 方法3: 从文章标题元素获取
        const titleElement = document.querySelector('#activity-name') ||
                            document.querySelector('.rich_media_title');
        if (titleElement) {
            let title = titleElement.textContent.trim();
            title = cleanTitle(title);
            return title;
        }

        return '微信公众号音频';
    }

    // 清理文件名（移除非法字符）
    function sanitizeFilename(filename) {
        return filename.replace(/[<>:"/\\|?*]/g, '_')
                      .replace(/\s+/g, ' ')
                      .trim();
    }

    // 查找音频ID
    function findAudioIds() {
        const audioIds = [];

        // 方法1: 从voice_encode_fileid属性中查找
        const voiceElements = document.querySelectorAll('[voice_encode_fileid]');
        voiceElements.forEach(element => {
            const audioId = element.getAttribute('voice_encode_fileid');
            if (audioId && audioId.length > 10) {
                audioIds.push(audioId);
            }
        });

        // 方法2: 从页面HTML中正则匹配
        const html = document.documentElement.outerHTML;
        const regex = /voice_encode_fileid="([^"]+)"/g;
        let match;
        while ((match = regex.exec(html)) !== null) {
            if (match[1] && match[1].length > 10 && !audioIds.includes(match[1])) {
                audioIds.push(match[1]);
            }
        }

        // 方法3: 从JavaScript变量中查找
        const jsRegex = /voice_encode_fileid[^=]*=\s*["']([^"']+)["']/g;
        let jsMatch;
        while ((jsMatch = jsRegex.exec(html)) !== null) {
            if (jsMatch[1] && jsMatch[1].length > 10 && !audioIds.includes(jsMatch[1])) {
                audioIds.push(jsMatch[1]);
            }
        }

        return [...new Set(audioIds)]; // 去重
    }

    // 生成下载链接
    function generateDownloadUrl(audioId) {
        return `[url]https://res.wx.qq.com/voice/getvoice?mediaid=[/url]${audioId}`;
    }

    // 下载音频
    function downloadAudio(audioId, title, index, total, button) {
        const downloadUrl = generateDownloadUrl(audioId);
        const statusSpan = button.parentNode.querySelector('.download-status');

        button.disabled = true;
        statusSpan.textContent = '下载中...';

        GM_xmlhttpRequest({
            method: 'GET',
            url: downloadUrl,
            responseType: 'blob',
            headers: {
                'Referer': window.location.href,
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
            },
            onload: function(response) {
                if (response.status === 200) {
                    const blob = response.response;

                    // 生成文件名
                    let filename = sanitizeFilename(title);
                    if (total > 1) {
                        filename = `${filename}_${index + 1}`;
                    }
                    filename += '.mp3';

                    // 使用FileSaver.js下载文件
                    saveAs(blob, filename);

                    statusSpan.textContent = '下载完成！';
                    setTimeout(() => {
                        statusSpan.textContent = '';
                        button.disabled = false;
                    }, 2000);
                } else {
                    statusSpan.textContent = '下载失败：' + response.status;
                    button.disabled = false;
                }
            },
            onerror: function(error) {
                statusSpan.textContent = '下载错误';
                button.disabled = false;
            },
            ontimeout: function() {
                statusSpan.textContent = '下载超时';
                button.disabled = false;
            }
        });
    }

    // 创建下载界面
    function createDownloadInterface() {
        const audioIds = findAudioIds();
        const articleTitle = getArticleTitle();

        if (audioIds.length === 0) {
            console.log('未找到音频ID');
            return;
        }

        // 创建下载容器
        const container = document.createElement('div');
        container.className = 'audio-download-container';
        container.innerHTML = `
            <h3 style="margin: 0 0 10px 0; color: #333;">音频下载</h3>
            <div style="font-size: 12px; color: #666; margin-bottom: 10px;">
                找到 ${audioIds.length} 个音频
            </div>
            <div class="filename-preview">
                文件名预览: <strong>${articleTitle}${audioIds.length > 1 ? '_序号' : ''}.mp3</strong>
            </div>
        `;

        // 为每个音频创建下载按钮
        audioIds.forEach((audioId, index) => {
            const audioDiv = document.createElement('div');
            audioDiv.style.marginBottom = '10px';
            audioDiv.style.padding = '8px';
            audioDiv.style.backgroundColor = 'white';
            audioDiv.style.borderRadius = '4px';

            const button = document.createElement('button');
            button.className = 'audio-download-btn';
            button.textContent = `下载音频 ${index + 1}`;

            const statusSpan = document.createElement('span');
            statusSpan.className = 'download-status';

            const infoDiv = document.createElement('div');
            infoDiv.className = 'audio-info';
            infoDiv.textContent = `ID: ${audioId.substring(0, 20)}...`;

            button.onclick = () => downloadAudio(audioId, articleTitle, index, audioIds.length, button);

            audioDiv.appendChild(button);
            audioDiv.appendChild(statusSpan);
            audioDiv.appendChild(infoDiv);
            container.appendChild(audioDiv);
        });

        // 将下载界面插入到页面合适位置
        const articleContent = document.getElementById('js_content') ||
                              document.querySelector('.rich_media_content') ||
                              document.querySelector('#page-content') ||
                              document.body;

        // 尝试插入到文章标题之后
        const titleElement = document.getElementById('activity-name') ||
                           document.querySelector('.rich_media_title');
        if (titleElement && titleElement.parentNode) {
            titleElement.parentNode.insertBefore(container, titleElement.nextSibling);
        } else {
            articleContent.insertBefore(container, articleContent.firstChild);
        }
    }

    // 页面加载完成后执行
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', createDownloadInterface);
    } else {
        createDownloadInterface();
    }

    // 监听页面变化（单页应用）
    let lastUrl = location.href;
    new MutationObserver(() => {
        const url = location.href;
        if (url !== lastUrl) {
            lastUrl = url;
            // 移除旧的下载界面
            const oldContainer = document.querySelector('.audio-download-container');
            if (oldContainer) {
                oldContainer.remove();
            }
            setTimeout(createDownloadInterface, 1000);
        }
    }).observe(document, {subtree: true, childList: true});

})();